package com.yx.front.security.service.impl;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.yx.front.config.global.BizException;
import com.yx.front.config.global.CommonResult;
import com.yx.front.converter.SysUserConverter;
import com.yx.front.model.SysUser;
import com.yx.front.model.SysUserRoleRelation;
import com.yx.front.model.param.SysUserParam;
import com.yx.front.security.LoginUser;
import com.yx.front.security.service.LoginService;
import com.yx.front.service.SysUserRoleRelationService;
import com.yx.front.service.SysUserService;
import com.yx.front.utils.JwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @author YangXiong
 */
@Service
@Slf4j
public class LoginServiceImpl implements LoginService {
    @Resource
    private RedisTemplate<String, String> redisTemplate;
    @Resource
    private AuthenticationManager authenticationManager;
    @Resource
    private SysUserService sysUserService;
    @Resource
    private SysUserConverter sysUserConverter;
    @Resource
    private SysUserRoleRelationService userRoleRelationService;

    @Override
    public CommonResult<HashMap<String, String>> login(SysUserParam sysUser) {
        checkCode(sysUser);
        Authentication authentication;
        try {
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(sysUser.getAccount(), sysUser.getPassword());
            authentication = authenticationManager.authenticate(authenticationToken);
        } catch (Exception e) {
            throw new BizException(e.getMessage());
        }
        if (Objects.isNull(authentication)) {
            throw new BizException("登录失败");
        }
        LoginUser user = (LoginUser) authentication.getPrincipal();
        SysUser returnUser = user.getSysUser();
        String token = JwtUtil.createJwt(returnUser.getId().toString());
        HashMap<String, String> map = new HashMap<>(4);
        map.put("token", token);
        map.put("userName", returnUser.getUserName());
        map.put("avatar", returnUser.getAvatar());
        //写入缓存
        Long userId = returnUser.getId();
        redisTemplate.opsForValue().set("login:" + userId, JSON.toJSONString(user), 10, TimeUnit.MINUTES);
        //更新登录时间
        LambdaUpdateWrapper<SysUser> wrapper = new LambdaUpdateWrapper<SysUser>().eq(SysUser::getId, returnUser.getId())
                .set(SysUser::getLastLoginTime, DateUtil.date());
        sysUserService.update(wrapper);
        return CommonResult.success(map);
    }

    private void checkCode(SysUserParam sysUser) {
        //判断验证码是否正确
        String code = sysUser.getCode();
        String uuid = sysUser.getUuid();
        String key = redisTemplate.opsForValue().get(uuid);
        if(Objects.isNull(key)){
            throw new BizException("验证码过期");
        }
        if (!Objects.equals(code.toLowerCase(), key)) {
            throw new BizException("验证码错误");
        }
    }

    @Override
    public CommonResult<String> logout() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        Long userId = loginUser.getSysUser().getId();
        redisTemplate.delete("login:" + userId);
        return CommonResult.success("注销成功");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public CommonResult<String> register(SysUserParam param) {
        if (Objects.isNull(param)) {
            throw new BizException("参数不能为空");
        }
        checkCode(param);
        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysUser::getAccount, param.getAccount());
        SysUser user = sysUserService.getOne(queryWrapper);
        if (Objects.nonNull(user)) {
            throw new BizException("账号已经存在，换一个试试");
        }
        //设置默认昵称
        param.setUserName(UUID.randomUUID().toString());
        SysUser sysUser = sysUserConverter.getSysUser(param);
        boolean save = sysUserService.save(sysUser);
        //设置默认权限 MP会自动返回主键 为了确保健壮性，做判断
        boolean ok = setRole(sysUser);
        if (save && ok ) {
            return CommonResult.success("注册成功");
        }
        return CommonResult.fail("注册失败，请稍后重试");
    }

    private boolean setRole(SysUser sysUser) {
        SysUserRoleRelation userRoleRelation = new SysUserRoleRelation();
        userRoleRelation.setRoleId(2L);
        userRoleRelation.setUserId(sysUser.getId());
        return userRoleRelationService.save(userRoleRelation);
    }
}
